package com.evil.account.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.evil.account.api.RemoteEnterpriseService;
import com.evil.account.mapper.EnterpriseMapper;
import com.evil.account.mapper.UserEnterpriseMapper;
import com.evil.account.mapper.UserMapper;
import com.evil.account.pojo.dto.enterprise.EnterpriseBaseInfoResp;
import com.evil.account.pojo.entity.Enterprise;
import com.evil.account.pojo.entity.User;
import com.evil.account.pojo.entity.UserEnterprise;
import com.evil.account.service.AuthUserService;
import com.evil.account.service.EnterpriseService;
import com.evil.account.service.TokenService;
import com.evil.account.service.UserEnterpriseService;
import com.evil.account.util.EnterpriseUtil;
import com.evil.common.account.bo.AuthUserBO;
import com.evil.common.account.dto.enterprise.*;
import com.evil.common.account.dto.user.UserBaseRespDTO;
import com.evil.common.account.dto.user.UserEnterpriseDTO;
import com.evil.common.account.util.LoginUtil;
import com.evil.common.core.constant.RedisConstant;
import com.evil.common.core.dto.FindByIdsReqDTO;
import com.evil.common.core.entity.QueryModel;
import com.evil.common.core.entity.TokenInfo;
import com.evil.common.core.enums.RCodeEnum;
import com.evil.common.core.enums.SwitchEnum;
import com.evil.common.core.exception.BusinessException;
import com.evil.common.core.util.RedisKeyUtil;
import com.evil.common.core.util.RedisUtil;
import com.evil.common.core.util.StreamUtil;
import com.evil.common.file.dto.FileRespDTO;
import com.evil.file.api.RemoteFileService;
import com.github.pagehelper.PageInfo;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * 企业表
 *
 * @author liyang
 * @date 2022-08-08 00:00
 */
@Slf4j
@RestController
@AllArgsConstructor
public class EnterpriseServiceImpl extends ServiceImpl<EnterpriseMapper, Enterprise> implements EnterpriseService, RemoteEnterpriseService {

    private final LoginUtil loginUtil;

    private final RedisUtil redisUtil;

    private final UserMapper userMapper;

    private final UserEnterpriseMapper userEnterpriseMapper;

    private final UserEnterpriseService userEnterpriseService;

    private final TokenService tokenService;

    private final AuthUserService authUserService;

    private final AccountLogServiceImpl accountLogService;

    private final RemoteFileService remoteFileService;

    /**
     * 通过企业id查询企业信息
     *
     * @param enterpriseId 企业id
     * @return enterprise
     */
    @Override
    public Optional<Enterprise> isExistById(Long enterpriseId) {
        return this.baseMapper.isExistById(enterpriseId);
    }

    /**
     * 通过企业ids查询企业信息
     *
     * @param findByIdsReqDTO findByIdsReqDTO
     * @return enterprise
     */
    @Override
    public List<Enterprise> findByIds(FindByIdsReqDTO findByIdsReqDTO) {
        return this.baseMapper.findByIds(findByIdsReqDTO.getIds(), findByIdsReqDTO.getFilterDeleted());
    }

    /**
     * 通过企业ids查询企业基础信息
     *
     * @param findByIdsReqDTO findByIdsReqDTO
     * @return enterprise
     */
    @Override
    public List<EnterpriseBaseRespDTO> findBaseByIds(FindByIdsReqDTO findByIdsReqDTO) {
        if (findByIdsReqDTO.getCache()) {
            return this.baseMapper.findBaseByIds_Cache(findByIdsReqDTO.getIds(), findByIdsReqDTO.getFilterDeleted());
        } else {
            return this.baseMapper.findBaseByIds(findByIdsReqDTO.getIds(), findByIdsReqDTO.getFilterDeleted());
        }
    }

    /**
     * 通过企业ids查询企业信息
     *
     * @param findByIdsReqDTO findByIdsReqDTO
     * @return enterprise
     */
    @Override
    public Map<Long, Enterprise> findMapByIds(FindByIdsReqDTO findByIdsReqDTO) {
        return this.baseMapper.findMapByIds(findByIdsReqDTO.getIds(), findByIdsReqDTO.getFilterDeleted());
    }

    /**
     * 通过企业ids查询企业基础信息
     *
     * @param findByIdsReqDTO findByIdsReqDTO
     * @return enterprise
     */
    @Override
    public Map<Long, EnterpriseBaseRespDTO> findBaseMapByIds(FindByIdsReqDTO findByIdsReqDTO) {
        return StreamUtil.toMapK(this.findBaseByIds(findByIdsReqDTO), EnterpriseBaseRespDTO::getEnterpriseId);
    }

    @Override
    public SystemInfoRespDTO loginSystemInfo() {
        EnterpriseBaseInfoResp enterpriseBaseInfoResp = this.baseMapper.platformEnterprise()
                .orElseThrow(() -> new BusinessException(RCodeEnum.PLATFORM_NOT_EXIST));
        SystemInfoRespDTO systemInfoRespDTO = new SystemInfoRespDTO();
        systemInfoRespDTO.setSystemName(enterpriseBaseInfoResp.getSystemName());
        // 登录LOGO图片
        Optional.ofNullable(enterpriseBaseInfoResp.getLoginLogoFileId()).flatMap(remoteFileService::isExistBaseByFileId)
                .ifPresent(f -> systemInfoRespDTO.setSystemLogoFileUrl(f.getFileUrl()));
        return systemInfoRespDTO;
    }

    /**
     * 当前登录用户企业基础信息
     *
     * @return EnterpriseBaseInfoResp
     */
    @Override
    public EnterpriseBaseInfoResp loginEnterpriseInfo() {
        EnterpriseBaseInfoResp enterpriseBaseInfoResp = this.baseMapper.findBaseInfoById(loginUtil.getLoginEnterpriseId())
                .orElseThrow(() -> new BusinessException(RCodeEnum.ERROR_UNAUTHENTICATED));

        // 登录LOGO图片id
        Optional.ofNullable(enterpriseBaseInfoResp.getLoginLogoFileId()).flatMap(remoteFileService::isExistBaseByFileId)
                .ifPresent(enterpriseBaseInfoResp::setLoginLogoFile);
        // 系统LOGO图片id
        Optional.ofNullable(enterpriseBaseInfoResp.getSystemLogoFileId()).flatMap(remoteFileService::isExistBaseByFileId)
                .ifPresent(enterpriseBaseInfoResp::setSystemLogoFile);
        // 导出LOGO图片id
        Optional.ofNullable(enterpriseBaseInfoResp.getExportLogoFileId()).flatMap(remoteFileService::isExistBaseByFileId)
                .ifPresent(enterpriseBaseInfoResp::setExportLogoFile);

        return enterpriseBaseInfoResp;
    }

    /**
     * 查询管理员列表
     *
     * @param queryModel queryModel
     * @return UserBaseRespDTO
     */
    @Override
    public PageInfo<UserBaseRespDTO> enterpriseManagerList(QueryModel<EnterpriseManagerPageReqDTO> queryModel) {
        EnterpriseManagerPageReqDTO param = queryModel.getParam();
        param.setEnterpriseId(loginUtil.getParamEnterpriseId(param.getEnterpriseId()));
        return userEnterpriseMapper.enterpriseManagerPage(queryModel);
    }

    /**
     * 增加/移除企业管理员
     *
     * @param handleEnterpriseManagerReqDTO handleEnterpriseManagerReqDTO
     */
    @Override
    public void handleEnterpriseManager(HandleEnterpriseManagerReqDTO handleEnterpriseManagerReqDTO) {
        // 是否是企业管理员
        userEnterpriseService.checkEnterpriseManager(loginUtil.getLoginUserEnterprise());

        Long userId = handleEnterpriseManagerReqDTO.getUserId();
        // 不传则获取当前登录的企业id
        Long enterpriseId = loginUtil.getParamEnterpriseId(handleEnterpriseManagerReqDTO.getEnterpriseId());
        handleEnterpriseManagerReqDTO.setEnterpriseId(enterpriseId);
        // 验证当前企业是否存在
        this.baseMapper.findById(enterpriseId);
        // 校验用户企业表中是否存在
        UserEnterprise userEnterprise = userEnterpriseMapper.findByEIdAndUId(enterpriseId, userId);
        // 若数据与参数一致,则不操作数据库
        if (!userEnterprise.getIsManager().equals(handleEnterpriseManagerReqDTO.getIsManager())) {
            userEnterprise.setIsManager(handleEnterpriseManagerReqDTO.getIsManager());
            accountLogService.saveAndCheck(userEnterpriseMapper, UserEnterprise::getEnterpriseId, userEnterprise);
        }
    }

    /**
     * 修改当前登录用户企业基础信息
     *
     * @param enterpriseReqDTO enterpriseReqDTO
     */
    @Override
    public void modifyLoginEnterpriseInfo(EnterpriseReqDTO enterpriseReqDTO) {
        UserEnterpriseDTO loginUserEnterprise = loginUtil.getLoginUserEnterprise();
        // 检查是否是管理员
        userEnterpriseService.checkEnterpriseManager(loginUserEnterprise);

        Enterprise enterprise = this.baseMapper.isExistById(loginUserEnterprise.getEnterpriseId())
                .filter(EnterpriseUtil::checkEnterprise)
                .orElseThrow(() -> new BusinessException(RCodeEnum.ERROR_UNAUTHENTICATED));

        BeanUtil.copyProperties(enterpriseReqDTO, enterprise);
        // 登录LOGO图片code
        if (StringUtils.isNotBlank(enterpriseReqDTO.getLoginLogoFileCode())) {
            FileRespDTO fileRespDTO = remoteFileService.findBaseByFileCode(enterpriseReqDTO.getLoginLogoFileCode());
            enterprise.setLoginLogoFileId(fileRespDTO.getFileId());
        }
        // 系统LOGO图片code
        if (StringUtils.isNotBlank(enterpriseReqDTO.getSystemLogoFileCode())) {
            FileRespDTO fileRespDTO = remoteFileService.findBaseByFileCode(enterpriseReqDTO.getSystemLogoFileCode());
            enterprise.setSystemLogoFileId(fileRespDTO.getFileId());
        }
        // 导出LOGO图片code
        if (StringUtils.isNotBlank(enterpriseReqDTO.getExportLogoFileCode())) {
            FileRespDTO fileRespDTO = remoteFileService.findBaseByFileCode(enterpriseReqDTO.getExportLogoFileCode());
            enterprise.setExportLogoFileId(fileRespDTO.getFileId());
        }

        accountLogService.saveAndCheck(this.baseMapper, Enterprise::getEnterpriseId, enterprise);
    }

    /**
     * 新增企业
     *
     * @param addEnterpriseReqDTO addEnterpriseReqDTO
     */
    @Override
    public void add(AddEnterpriseReqDTO addEnterpriseReqDTO) {
        Enterprise enterprise = BeanUtil.copyProperties(addEnterpriseReqDTO, Enterprise.class);
        if (StringUtils.isNotBlank(addEnterpriseReqDTO.getSystemLogoFileCode())) {
            remoteFileService.isExistBaseByFileCode(addEnterpriseReqDTO.getSystemLogoFileCode())
                    .ifPresent(f -> enterprise.setSystemLogoFileId(f.getFileId()));
        }
        accountLogService.saveAndCheck(this.baseMapper, Enterprise::getEnterpriseId, enterprise);
    }

    /**
     * 编辑企业
     *
     * @param modifyEnterpriseReqDTO modifyEnterpriseReqDTO
     */
    @Override
    public void modify(ModifyEnterpriseReqDTO modifyEnterpriseReqDTO) {
        Long enterpriseId = loginUtil.getParamEnterpriseId(modifyEnterpriseReqDTO.getEnterpriseId());
        Enterprise enterprise = this.baseMapper.findNormalById(enterpriseId);
        BeanUtil.copyProperties(modifyEnterpriseReqDTO, enterprise);
        // code不为空
        if (StringUtils.isNotBlank(modifyEnterpriseReqDTO.getSystemLogoFileCode())) {
            remoteFileService.isExistBaseByFileCode(modifyEnterpriseReqDTO.getSystemLogoFileCode())
                    .ifPresent(f -> enterprise.setSystemLogoFileId(f.getFileId()));
        }
        accountLogService.saveAndCheck(this.baseMapper, Enterprise::getEnterpriseId, enterprise);
    }

    /**
     * 修改企业logo
     *
     * @param modifyEnterpriseLogoReqDTO modifyEnterpriseLogoReqDTO
     */
    @Override
    public void modifyEnterpriseLogo(ModifyEnterpriseLogoReqDTO modifyEnterpriseLogoReqDTO) {
        Long enterpriseId = loginUtil.getParamEnterpriseId(modifyEnterpriseLogoReqDTO.getEnterpriseId());

        Enterprise enterprise = this.baseMapper.findNormalById(enterpriseId);

        if (StringUtils.isNotBlank(modifyEnterpriseLogoReqDTO.getSystemLogoFileCode())) {
            remoteFileService.isExistBaseByFileCode(modifyEnterpriseLogoReqDTO.getSystemLogoFileCode())
                    .ifPresent(f -> enterprise.setSystemLogoFileId(f.getFileId()));
        }
        accountLogService.saveAndCheck(this.baseMapper, Enterprise::getEnterpriseId, enterprise);
    }

    /**
     * 获取企业列表
     *
     * @param queryModel queryModel
     * @return PageInfo
     */
    @Override
    public PageInfo<EnterprisePageRespDTO> page(QueryModel<EnterprisePageReqDTO> queryModel) {
        EnterprisePageReqDTO param = queryModel.getParam();
        param.setEnterpriseId(loginUtil.getParamEnterpriseId(param.getEnterpriseId()));
        return this.baseMapper.enterprisePage(queryModel);
    }

    /**
     * 删除企业
     *
     * @param deleteEnterpriseReqDTO deleteEnterpriseReqDTO
     */
    @Override
    public void delete(DeleteEnterpriseReqDTO deleteEnterpriseReqDTO) {
        Long enterpriseId = loginUtil.getParamEnterpriseId(deleteEnterpriseReqDTO.getEnterpriseId());

        Enterprise enterprise = this.baseMapper.findNormalById(enterpriseId);
        enterprise.setIsDeleted(SwitchEnum.YES.getId());
        accountLogService.saveAndCheck(this.baseMapper, Enterprise::getEnterpriseId, enterprise);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AuthUserBO modifyLoginEnterprise(Long enterpriseId) {
        Enterprise enterprise = this.baseMapper.findNormalById(enterpriseId);
        UserBaseRespDTO loginUserBase = loginUtil.getLoginUserBase();
        String token = loginUtil.getLoginToken();
        Long loginEnterpriseId = loginUtil.getLoginEnterpriseId();

        User user = userMapper.findNormalById(loginUserBase.getUserId());
        // 验证更改的企业是否合法
        this.verifyChangeEnterpriseInfo(enterprise);
        // 获取tokenInfo,更改其中信息
        String key = RedisKeyUtil.accessTokenKey(token);
        TokenInfo tokenInfo = (TokenInfo) redisUtil.get(key);
        tokenInfo.setEnterpriseId(enterprise.getEnterpriseId());
        // 重新set到redis
        redisUtil.set(key, tokenInfo, RedisConstant.TOKEN_EXPIRE_IN_SECOND);
        tokenService.switchEnterpriseTokenHandler(loginEnterpriseId, user.getUserId(), token, enterprise.getEnterpriseId());
        // 封装返回信息
        AuthUserBO authUserBO = authUserService.getAuthUserBaseInfo(user, token, enterprise);
        // 修改默认企业
        UserEnterprise userEnterprise = userEnterpriseMapper.findByEIdAndUId(enterprise.getEnterpriseId(), user.getUserId());
        authUserService.modifyDefaultEnterprise(userEnterprise);
        return authUserBO;
    }

    private void verifyChangeEnterpriseInfo(Enterprise enterprise) {
        UserEnterpriseDTO loginUserEnterprise = loginUtil.getLoginUserEnterprise();
        Long userId = loginUtil.getLoginUserId();
        // 切换企业是否存在
        if (null == enterprise) {
            throw new BusinessException(RCodeEnum.ENTERPRISE_NOT_EXIST);
        }
        // 企业是否是删除状态
        if (enterprise.getIsDeleted().equals(SwitchEnum.YES.getId())) {
            throw new BusinessException(RCodeEnum.ENTERPRISE_NOT_EXIST);
        }
        // 企业id是否有变动
        if (enterprise.getEnterpriseId().equals(loginUserEnterprise.getEnterpriseId())) {
            throw new BusinessException(RCodeEnum.ERROR_PARAMETER, "已在当前企业登录,信息未变更");
        }
        // 用户是否在企业
        userEnterpriseService.getBaseMapper().isExistNormalByEIdAndUId(enterprise.getEnterpriseId(), userId);
    }
}
